unit MahStringBuilder;
interface

// ==========================================================================
// from:http://delphi.cjcsoft.net/viewthread.php?tid=44016
//Title: Delphi Implementation of C# StringBuilder (Fast String Concat)
//
//Question: Those of you who use C# know that to concatenate a large number of strings takes forever unless you use the StringBulder class. This is a Delphi implementation of such and huge increase in performance can be gained by using it. On my machine the following timings were experienced.
//
//procedure TForm1.Button1Click(Sender: TObject);
//var oBuilder : TStringBuilder;
//    sString : string;
//    i,iCount : integer;
//begin
//  iCount := 10000;
//  oBuilder := TStringBuilder.Create;
//
//  for i := 1 to iCount do oBuilder.Append(IntToStr(i));
//  sString := oBuilder.AsString;
//  // 6 Milliseconds
//
//  sString := '';
//  for i := 1 to iCount do sString := sString + IntToStr(i);
//  // 404 Milliseconds
//
//  FreeAndNil(oBuilder);
//end;



// Implementation of C# StringBuilder class.
// Mike Heydon 2008
//
// Allow fast string concatenation without excessive memory rellocs.
// Default Initial Buffer Size is 4K and doubles for each reallocation, but
// can be set to a higher or lower value for performance if the size of
// the resulting string is predicatble.
//
// Example
//
// procedure TForm1.Button1Click(Sender: TObject);
// var oString : TStringBuilder;
//     i : integer;
// begin
//   oString := TStringBuilder.Create;
//   for i := 1 to 100 do oString.Append(IntToStr(i) + ' ');
//   oString.Append('100 Numbers ');
//   Memo1.Lines.Add(oString.AsString);
//   oString.Append('Some More ExtraText');
//   Memo1.Lines.Add(oString.AsString);
//   FreeAndNil(oString);
// end;
//
// ==========================================================================

type
     { TStringBuilder Class }
     TStringBuilder = class(TObject)
     private
       FBuffMax,
       FBuffSize,FIndex : integer;
       FBuffer : PChar;
       procedure _ExpandBuffer;
       function GetFString : string;
       procedure SetFString(const AString : string);
     public
       constructor Create(ABufferSize : integer = 4096);
       destructor Destroy; override;
       procedure Append(const AString : string);
       procedure Clear;
       property AsString : string read GetFString write SetFString;
     end;

// --------------------------------------------------------------------------
implementation


procedure TStringBuilder._ExpandBuffer;
begin
  FBuffSize := FBuffSize shl 1;
  FBuffMax := FBuffSize - 1;
  ReallocMem(FBuffer,FBuffSize);
end;


constructor TStringBuilder.Create(ABufferSize : integer = 4096);
begin
  inherited Create;

  if ABufferSize = 0 then FBuffSize := 1024
  else
    FBuffSize := ABufferSize;

  GetMem(FBuffer,FBuffSize);
  FBuffMax := FBuffSize - 1;
  FIndex := 0;
end;


destructor TStringBuilder.Destroy;
begin
  FreeMem(FBuffer);

  inherited Destroy;
end;


procedure TStringBuilder.Append(const AString : string);
var iLen : integer;
begin
  iLen := length(AString);
  if iLen + FIndex > FBuffMax then _ExpandBuffer;
  move(AString[1],FBuffer[FIndex],iLen);
  inc(FIndex,iLen);
end;


function TStringBuilder.GetFString : string;
begin
  FBuffer[FIndex] := #0;

  Result := FBuffer;
end;


procedure TStringBuilder.SetFString(const AString : string);
begin
  self.Clear;
  self.Append(AString);
end;


procedure TStringBuilder.Clear;
begin
  FIndex := 0;
end;

end.

